local lspkind = require("lspkind")

local cmp = require("cmp")
local luasnip = require("luasnip")
local snippet = require("lsp/snippet")
-- local suggestion = require('supermaven-nvim.completion_preview')

local parse = require("cmp.utils.snippet").parse
require("cmp.utils.snippet").parse = function(input)
	local ok, ret = pcall(parse, input)
	if ok then
		return ret
	end
	return snippet.snippet_preview(input)
end

require("cmp_git").setup()

local check_backspace = function()
	local line, col = unpack(vim.api.nvim_win_get_cursor(0))
	return col ~= 0 and vim.api.nvim_buf_get_text(0, line - 1, 0, line - 1, col, {})[1]:match("^%s*$") == nil
end

local winhighlight = {
	winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:PmenuSel",
}

vim.api.nvim_set_hl(0, "CmpItemKindSupermaven", { fg = "#E06C75" })

cmp.setup({
	snippet = {
		expand = function(args)
			luasnip.lsp_expand(args.body)
		end,
	},
	completion = {
		completeopt = "menu,menuone,noinsert,noselect",
	},
	mapping = {
		["<C-p>"] = cmp.mapping(cmp.mapping.select_prev_item(), { "i", "c" }),
		["<C-n>"] = cmp.mapping(cmp.mapping.select_next_item(), { "i", "c" }),
		["<C-d>"] = cmp.mapping(cmp.mapping.scroll_docs(-4), { "i", "c" }),
		["<C-f>"] = cmp.mapping(cmp.mapping.scroll_docs(4), { "i", "c" }),
		["<C-Space>"] = cmp.mapping(cmp.mapping.complete(), { "i", "c" }),
		["<C-e>"] = cmp.mapping({
			i = cmp.mapping.close(),
			c = cmp.mapping.close(),
		}),
		["<CR>"] = cmp.mapping.confirm({ select = true, behavior = cmp.SelectBehavior.Select }),
		["<Tab>"] = cmp.mapping(function(fallback)
			if cmp.visible() and check_backspace() then
				cmp.select_next_item()
			elseif luasnip.expand_or_jumpable() then
				luasnip.expand_or_jump()
			elseif luasnip.expandable() then
				luasnip.expand()
				-- elseif suggestion.has_suggestion() then
				--  		suggestion.on_accept_suggestion()
			else
				fallback()
			end
		end, {
			"i",
			"s",
		}),
		["<S-Tab>"] = cmp.mapping(function(fallback)
			if cmp.visible() then
				cmp.select_prev_item()
				-- elseif luasnip.jumpable(-1) then
				--   luasnip.jump(-1)
			else
				fallback()
			end
		end, {
			"i",
			"s",
		}),
	},
	sources = {
		{ name = "nvim_lsp" },
		{ name = "buffer",       { keyword_length = 4 } },
		-- { name = 'nvim_lua' },
		-- { name = "supermaven" },
		-- { name = "codeium",    max_item_count = 2 },  -- 会让cmp响应慢一点点
		{ name = "lazydev",      group_index = 0 },
		{ name = "path" },
		-- { name = "async_path" },
		{ name = "calc" },
		{ name = "emoji" },
		-- { name = 'cmp_tabnine' },
		{ name = "git" },
		-- { name = "luasnip" },
		-- { name = "otter" },
		{ name = "css-variables" },
		-- { name = 'digraphs' },
		-- { name = 'treesitter' },
		-- { name = 'look', keyword_length=4, option={convert_case=true, loud=true}},
	},
	formatting = {
		expandable_indicator = true,
		fields = { "kind", "abbr", "menu" },
		format = function(entry, vim_item)
			local highlights_info = require("colorful-menu").cmp_highlights(entry)

			-- if highlight_info==nil, which means missing ts parser, let's fallback to use default `vim_item.abbr`.
			-- What this plugin offers is two fields: `vim_item.abbr_hl_group` and `vim_item.abbr`.
			if highlights_info ~= nil then
				vim_item.abbr_hl_group = highlights_info.highlights
				vim_item.abbr = highlights_info.text
			end
			local kind = lspkind.cmp_format({
				symbol_map = { Copilot = "", Codeium = "⚡︎", Snippet = "", Keyword = "", Supermaven = "", },
				preset = "codicons",
				maxwidth = 40,
				before = require("tailwind-tools.cmp").lspkind_format,
			})(entry, vim_item)
			local strings = vim.split(vim_item.kind, "%s+", { trimempty = true })
			kind.kind = " " .. string.format("%s │", strings[1], strings[2]) .. " "
			return kind
		end,
	},
	window = {
		completion = cmp.config.window.bordered({
			col_offset = -3, -- align the abbr and word on cursor (due to fields order below)
			side_padding = 0,
			bordered = winhighlight,
		}),
		documentation = cmp.config.window.bordered(winhighlight),
	},
})

-- for autopairs
local cmp_autopairs = require("nvim-autopairs.completion.cmp")
cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done())

-- cmp.event:on("confirm_done", function(event)
--   if vim.tbl_contains({}, vim.bo.filetype) then
--     snippet.auto_brackets(event.entry)
--   end
-- end)
-- cmp.event:on("menu_opened", function(event)
--   snippet.add_missing_snippet_docs(event.window)
-- end)

cmp.setup.filetype("TelescopePrompt", {
	enabled = false,
})

cmp.setup.filetype("gitcommit", {
	sources = {
		{ name = "git",             max_item_count = 10 },
		{ name = "buffer",          max_item_count = 10 },
		{ name = "cmdline_history", max_item_count = 10 },
	},
})

cmp.setup.cmdline({ "/", "?" }, {
	mapping = cmp.mapping.preset.cmdline(),
	sources = {
		{ name = "buffer" },
		{ name = "cmdline_history" },
		{ name = "path" },
	},
})

cmp.setup.cmdline(":", {
	mapping = cmp.mapping.preset.cmdline(),
	sources = {
		{ name = "path" },
		{ name = "cmdline",        option = { ignore_cmds = {} } },
		{ name = "cmdline_history" },
	},
})

vim.api.nvim_create_autocmd({ "FileType" }, {
	pattern = "*.toml",
	callback = function()
		require("cmp").setup.buffer({ sources = { { name = "crates" } } })
	end,
	desc = "Add cmp source for toml",
})

vim.api.nvim_create_autocmd({ "FileType" }, {
	pattern = "*.json",
	callback = function()
		require("cmp").setup.buffer({ sources = { { name = "npm", keyword_length = 3 } } })
	end,
	desc = "Add cmp source for json",
})
